﻿using DesktopSwipeAnimationIsBack.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;

namespace DesktopSwipeAnimationIsBack
{
    internal static class Program
    {

        static bool triggled = false;
        static bool triggled2 = false;

        static int x1Function = 0;

        static bool triggledMovement = false;
        static int triggledMovementAcc = 0;
        
        static int beginX = 0;
        static float delta = 0;
        static System.Timers.Timer smoothUpdatingThread;
        static long lastUpdate = -1;
        static DateTime epoch = new DateTime(2022, 1, 1, 2, 2, 3);

        static bool triggedAltTab = false;

        static MouseBurstClicker mouseBurstClicker;
                

        static long SysClock
        {
            get { return (long)(DateTime.Now - epoch).TotalMilliseconds; }
        }

        [STAThread]
        static void Main()
        {
            smoothUpdatingThread = new System.Timers.Timer();
            smoothUpdatingThread.Interval = 450;
            smoothUpdatingThread.Enabled = false;
            mouseBurstClicker = new MouseBurstClicker();
            SwipeSimulator swipeSimulator = new SwipeSimulator();
            MouseHook hook = MouseHook.GetMouseHook();
            var handler = new MouseHook.MyMouseEventHandler((i, k, cancel) =>
            {
                if(i != MouseHook.WM_MOUSEMOVE)
                {
                    if(i == MouseHook.WM_XBUTTONDOWN || i == MouseHook.WM_XBUTTONUP)
                    {
                        cancel.Cancel = true;
                        if (k.mouseData == 65536)
                        {
                            triggled = i == MouseHook.WM_XBUTTONDOWN;
                            if (triggled)
                            {
                                Console.WriteLine("================ Triggled");
                                triggledMovement = false;
                                triggledMovementAcc = 0;
                                beginX = k.pt.x;
                                smoothUpdatingThread.Enabled = true;
                                Cursor.Hide();
                            }
                            else
                            {

                                smoothUpdatingThread.Enabled = false;
                                Console.WriteLine("================ Released");
                                if (triggledMovement) { 
                                swipeSimulator.Release(); }
                                Cursor.Show();
                                if (!triggledMovement)
                                {
                                    sendWinTab();
                                }
                            }
                        }
                        else
                        {
                            triggled2 = i == MouseHook.WM_XBUTTONDOWN;
                            if (triggled2)
                            {
                                x1Function = 0;
                                Console.WriteLine("X1DOWN");
                                triggedAltTab = false;
                            }
                            else {
                                Console.WriteLine("X1UP");
                                mouseBurstClicker.Stop();
                                if (triggedAltTab)
                                {
                                    triggedAltTab = false;
                                    Console.WriteLine("AltTab Released");
                                    KeyEmu(Keys.LMenu, false);
                                }
                            }
                        }
                    }
                    if (triggled2)
                    {


                        if ((k.flags & 0x1u) == 0)
                        {
                            if(x1Function == 0 || x1Function == 1)
                            {

                                cancel.Cancel = true;
                                if (i == MouseHook.WM_LBUTTONDOWN)
                                {
                                    x1Function = 1;
                                    Console.WriteLine(k.flags);
                                    Console.WriteLine("Burst Clicker Start");
                                    mouseBurstClicker.Start(10);
                                }
                                if (i == MouseHook.WM_LBUTTONUP)
                                {
                                    Console.WriteLine(k.flags);
                                    Console.WriteLine("Burst Clicker Stop");
                                    mouseBurstClicker.Stop();
                                }
                            }


                            if (x1Function == 0 || x1Function == 2)
                            {
                                if (i == MouseHook.WM_MOUSEWHEEL)
                                {
                                    if (triggedAltTab)
                                    {
                                        bool direction = (k.mouseData & 0x80000000u) != 0;

                                        if (!direction)
                                        {
                                            KeyEmu(Keys.LShiftKey, true);
                                        }

                                        KeyEmu(Keys.Tab, true);
                                        KeyEmu(Keys.Tab, false);
                                        if (!direction)
                                        {
                                            KeyEmu(Keys.LShiftKey, false);
                                        }
                                        cancel.Cancel = true;
                                    }
                                    else
                                    {
                                        x1Function = 2;
                                        Console.WriteLine("AltTab Triggered");
                                        KeyEmu(Keys.LMenu, true);
                                        KeyEmu(Keys.LShiftKey, true);
                                        KeyEmu(Keys.Tab, true);
                                        KeyEmu(Keys.Tab, false);
                                        KeyEmu(Keys.LShiftKey, false);
                                        Thread.Sleep(5);
                                        KeyEmu(Keys.Tab, true);
                                        KeyEmu(Keys.Tab, false);
                                        triggedAltTab = true;
                                    }


                                }
                            }
                        }
                        else
                        {
                            k.flags = k.flags & (~0x1u);
                        }
                        
                    }
                }
                else
                {
                    if (triggled)
                    {
                        lock (swipeSimulator)
                        {
                            if (!triggledMovement)
                            {
                                triggledMovementAcc += (k.pt.x - beginX);
                                if (Math.Abs(triggledMovementAcc) > 16) {
                                    triggledMovement = true;
                                    swipeSimulator.Aquire();
                                }
                            }
                            else
                            {

                                lastUpdate = SysClock;
                                swipeSimulator.Move((k.pt.x - beginX) * 4);
                            }
                        }
                        cancel.Cancel = true;
                    }
                   
                }
                
            });
            smoothUpdatingThread.Elapsed += delegate {
                if (triggled)
                {
                    lock (swipeSimulator)
                    {
                        if(SysClock - lastUpdate > 200)
                        {

                            swipeSimulator.Move(0);
                        }
                    }
                }

            };
            hook.AddMouseHandler(handler);
            hook.Start();
            NotifyIcon icon = new NotifyIcon();
            icon.Text = "鼠标桌面切";
            icon.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
            icon.Visible = true;
            ContextMenu menu = new ContextMenu();
            menu.MenuItems.Add("退出", onQuitClick);
            icon.ContextMenu = menu;
            Application.Run();
            hook.Stop();
            GC.KeepAlive(handler);
            GC.KeepAlive(icon);
            GC.KeepAlive(menu);
        }

        public static void onQuitClick(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private static void sendWinTab() {
            KeyEmu(Keys.LWin, true);
            KeyEmu(Keys.Tab, true);
            KeyEmu(Keys.Tab, false);
            KeyEmu(Keys.LWin, false);
        }

        public static void KeyEmu(Keys key,bool isDown)
        {
            keybd_event(key, 0, isDown ? KEYEVENTF_KEYDOWN : KEYEVENTF_KEYUP, 0);
        }

        public const uint KEYEVENTF_KEYUP = 2;
        public const uint KEYEVENTF_KEYDOWN = 0;
        [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
        public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
    }

    public class MouseBurstClicker
    {
        // 鼠标按键事件定义常量
        private const uint MOUSEEVENTF_LEFTDOWN = 0x02;
        private const uint MOUSEEVENTF_LEFTUP = 0x04;

        // 导入Windows API函数
        [DllImport("user32.dll")]
        private static extern void mouse_event(uint dwFlags, int dx, int dy, uint dwData, int dwExtraInfo);
        public const uint FLAG_SENDFROMME = 0x40000u;
        private System.Timers.Timer clickTimer;

        public MouseBurstClicker()
        {
            clickTimer = new System.Timers.Timer();
            clickTimer.Elapsed += ClickTimerElapsed;
        }

        public void Start(int interval)
        {
            clickTimer.Interval = interval;
            clickTimer.Start();
        }

        public void Stop()
        {
            clickTimer.Stop();
        }

        private void ClickTimerElapsed(object sender, ElapsedEventArgs e)
        {
            // 模拟连续鼠标按下和抬起左键
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
        }
    }
}
